package logic.algorithm.greedy;

import java.util.ArrayList;
import logic.algorithm.aco.NoNodeChoosenException;
import logic.objects.Connection;
import logic.objects.ConnectionArrayList;
import logic.objects.Node;
import logic.objects.Problem;

public class NearestNeighbor {
	private static Double shortestLoop = Double.MAX_VALUE;
	private static ArrayList<Node> solution=null;

	public static void solve(Problem problem) {
		ArrayList<Node> solution = getSolution(problem);
		saveShortestLoop(problem, solution);
		updatePheromone(problem, solution);
		updateBestTourSoFar(problem, solution);
		setSolution(solution);
	}
	public static ArrayList<Node> getSolution(){
		return solution;
	}
	private static void setSolution(ArrayList<Node> solutionUpdate){
		solution=solutionUpdate;
	}

	private static ArrayList<Node> getSolution(Problem problem) {
		problem.applyConnections();
		@SuppressWarnings("unchecked")
		ArrayList<Node> nodesLeft = (ArrayList<Node>) problem.getNodes()
				.clone();
		ArrayList<Node> nodesDone = new ArrayList<Node>();
		Node aktNode = nodesLeft.remove(0);
		nodesDone.add(aktNode);
		while (nodesLeft.size() > 0) {
			Integer index = null;
			int i = 0;
			Double minDist = Double.MAX_VALUE;
			Double length;
			for (Node node : nodesLeft) {
				if (aktNode.getId() != node.getId()) {
					length = problem.getConnections()
							.get(aktNode.getId(), node.getId()).getLength();
					if (minDist > length) {
						minDist = length;
						index = i;

					}
				}
				i++;
			}
			if (index == null) {
				throw (new NoNodeChoosenException());
			}
			int indexInt = index;
			aktNode = nodesLeft.remove(indexInt);
			nodesDone.add(aktNode);
		}

		return nodesDone;
	}

	private static void updatePheromone(Problem problem, ArrayList<Node> nodes) {
		ConnectionArrayList connections = problem.getConnections();
		for (int i = 0; i < connections.getSizeX(); i++) {
			for (int j = 0; j < connections.getSizeY(); j++) {
				if (i != j) {
					Connection con = connections.get(i, j);
					con.setPheromon(0);
				}
			}
		}
		for (int i = 1; i < nodes.size(); i++) {
			connections.get(nodes.get(i - 1).getId(), nodes.get(i).getId())
					.setPheromon(100);
		}
		connections.get(nodes.get(nodes.size() - 1).getId(),
				nodes.get(0).getId()).setPheromon(100);
	}

	private static void saveShortestLoop(Problem problem,
			ArrayList<Node> solution) {
		Connection con;
		Double total = 0.0;
		for (int i = 1; i < solution.size(); i++) {
			con = problem.getConnections().get(solution.get(i - 1).getId(),
					solution.get(i).getId());
			total += con.getLength();
		}
		con = problem.getConnections().get(
				solution.get(solution.size() - 1).getId(),
				solution.get(0).getId());
		total += con.getLength();
		shortestLoop = total;
	}

	public static Double getShortestLoop() {
		return shortestLoop;
	}

	private static void updateBestTourSoFar(Problem problem,
			ArrayList<Node> solution) {
		problem.setBestTourSoFarValue(shortestLoop);
		problem.setBestTourSoFar(solution);
	}
	public static void reset(){
		solution=null;
		shortestLoop=Double.MAX_VALUE;
	}
}
